import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;


import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Font;




import java.text.Collator;
import java.util.Locale;

/**
 * Main program - GUI class
 *
 */

public class GUI {
   private static final ThreadPool pool = new ThreadPool(5);
   private static final UserState currentUser = new UserState();
   
   // Main display
   final static SWTUtil SWTwin = new SWTUtil();

   // Default Database setting
   final private static String defDBUser="DB_SONGS_I_LIKE";
   final private static String defDBPassword="qwe";
   final private static String defDBHostName="localhost";
   final private static String defDBPort="1555";
   final private static String defDBSID="csodb";
   
   private static boolean DBflag=false;
   
   // Create new DB Setting object with default settings
   final private static DBSettings dbSettingsObj = new DBSettings(defDBUser, defDBPassword, defDBHostName, defDBPort, defDBSID);   
   
   // Save "edit song" arguments
   private static String songNameSelected="";
   private static String artistNameSelected="";
   private static String cdNameSelected="";
   private static String genreNameSelected="";
   private static String yearSelected="";
   private static int rowNumSelected=-1;
   
   // Logout flag
   private static int logout;
   
   //logger arguments
   private static logger myLogger=null;
   private static boolean logReady=false;
   
   // Mapping of continents and genres lists retrieved from the DB
   private static Map<Object, Integer> continents;
   private static Map<Object, Integer> genres;
   
   // Search Page Results Map
	private static Map<Integer,Song> resultsQuery;
   
   // Recommendation Page Results Map
   private static Map<Integer,Song> resultsQueryRecom;
   
   // Basic CF Page
   static Map<Integer,Song> resultsQueryCF;

   // Number of Elements a user has to fill (required) on the sign up page
   // in order for the "Sign Up" button to be enabled
   private static final int numOfElements=4;
   
   // Results page functionality arguments
   private static int countSelection=0;
   private static int resultOffset=0;
   private static int resultOffsetRecom=0;
   private static int resultOffsetCF=0;
   private static final int RESULT_PER_PAGE=100;
   
   static private DBOperations DBInstance = null;
   
   // Upload file string
   private static String selectedFile;
   
   // Exact phrase on search page boolean arguments
   private static boolean searchArtistCheck;
   private static boolean searchCDCheck;
   private static boolean searchSongCheck;
   
   // Arguments per search query
   private static String searchArtistName;
   private static String searchCDName;
   private static String searchsongName;
   private static String searchChosenGenre;
   private static String searchChosenDecade;
   private static int searchGenreId;
   private static int searchDecade;
   

   public static void main(String[] args){

	   try {
		   // Open new log file
 			myLogger = new logger("log.txt");
 		} 
 		catch (SecurityException e1) {
 		} 
 		catch (IOException e1) 
 			{
 		}
 		
 		try
 		{
 			logReady=(myLogger!=null);
 			showDBLoginShell();
 			if (DBflag) {
	 			do {
	 				// Set logged in to false before showing log in page
	 				currentUser.setLoggedin(false);
	 				countSelection=0;
		 			// Send user to login page
		 			showLoginShell();
		 			logout=0;
		 			// If user has given correct login info, redirect to main window
		 			if (currentUser.isLoggedin())
		 				showMainShell();
	 			} while(logout==1);
 			}
 			// Stopping Thread Pool
			pool.stopRequestAllWorkers();
			// Releasing connection pool
			if (DBInstance!=null)
				DBInstance.releasePool();
			
 			SWTUtil.closeDisplay();
 			System.exit(0);
 		}
 		catch (Exception e)
 		{
 			if (logReady)
 				{
 				myLogger.log(2,"unknown error has occured, please check the logs for mr details");
 				myLogger.log(2, e.getMessage());
 				}
 		}
 		finally
  		{
  			if (logReady) myLogger.closeFileHandler();
  		}
	}
   
   /**
	 * Upon opening the program, DB login page generated by this function 
	 * will be presented to the user.
	 */
	public static void showDBLoginShell(){
		final Shell shell = SWTwin.getShell();
		final Display display = shell.getDisplay();
		
		shell.setText("DB Connection");
		shell.setLayout(new GridLayout(3, true)); // 2 columns, same width
		
		// User
		new Label(shell, SWT.RIGHT).setText("DB Username: ");
	    final Text DBuserText = new Text(shell, SWT.BORDER);
	    final GridData DBuserSpan = new GridData(GridData.FILL_HORIZONTAL);
	    DBuserSpan.horizontalSpan = 2;
	    DBuserText.setLayoutData(DBuserSpan);
	    DBuserText.setText(defDBUser);
		
	    // Password
	    new Label(shell, SWT.RIGHT).setText("Password: ");
	    final Text DBpasswordText = new Text(shell, SWT.BORDER | SWT.PASSWORD);
	    final GridData DBpassSpan = new GridData(GridData.FILL_HORIZONTAL);
	    DBpassSpan.horizontalSpan = 2;
	    DBpasswordText.setLayoutData(DBpassSpan);
	    DBpasswordText.setText(defDBPassword);
	    
	    // Hostname
	    new Label(shell, SWT.RIGHT).setText("Hostname: ");
	    final Text DBHostnameText = new Text(shell, SWT.BORDER);
	    final GridData DBHostnameSpan = new GridData(GridData.FILL_HORIZONTAL);
	    DBHostnameSpan.horizontalSpan = 2;
	    DBHostnameText.setLayoutData(DBHostnameSpan);
	    DBHostnameText.setText(defDBHostName);
	    
	    // Port
	    new Label(shell, SWT.RIGHT).setText("Port: ");
	    final Text DBPortText = new Text(shell, SWT.BORDER);
	    final GridData DBPortSpan = new GridData(GridData.FILL_HORIZONTAL);
	    DBPortSpan.horizontalSpan = 2;
	    DBPortText.setLayoutData(DBPortSpan);
	    DBPortText.setText(defDBPort);
	    
	    // SID
	    new Label(shell, SWT.RIGHT).setText("SID: ");
	    final Text DBSIDText = new Text(shell, SWT.BORDER);
	    final GridData DBSIDSpan = new GridData(GridData.FILL_HORIZONTAL);
	    DBSIDSpan.horizontalSpan = 2;
	    DBSIDText.setLayoutData(DBSIDSpan);
	    DBSIDText.setText(defDBSID);
		
	    // Connection status label
	    final Label statusLabel = new Label(shell, SWT.CENTER);
	    final GridData statusLabelSpan = new GridData(GridData.FILL_HORIZONTAL);
	    statusLabelSpan.horizontalSpan = 3;
	    statusLabel.setLayoutData(statusLabelSpan);
	    
	    // Login Button
	    final Button loginButton = new Button(shell, SWT.PUSH | SWT.FLAT);
	    loginButton.setText("Login to DB");
	    final GridData DBloginButtonGrid = new GridData(GridData.FILL_HORIZONTAL);
	    DBloginButtonGrid.horizontalSpan = 3;
	    // span 2 columns
	    loginButton.setLayoutData(DBloginButtonGrid);
	    
	    
	    //DB login button listener
	    loginButton.addSelectionListener(new SelectionAdapter() {
			   public void widgetSelected(SelectionEvent e) {
				   // Set the DB connection with the given details
				   dbSettingsObj.setDBUser(DBuserText.getText());
				   dbSettingsObj.setDBPassword(DBpasswordText.getText());
				   dbSettingsObj.setDBHostName(DBHostnameText.getText());
				   dbSettingsObj.setDBPort(DBPortText.getText());
				   dbSettingsObj.setDBSID(DBSIDText.getText());
				   // Disable button to prevent multiple clicks during validation
				   loginButton.setEnabled(false);
				   try {
					pool.execute(new Runnable(){
						   public void run() {
							   DBInstance = DBOperations.getInstance(dbSettingsObj.getDBUser(), dbSettingsObj.getDBPassword(),dbSettingsObj.getDBHostName(), dbSettingsObj.getDBPort(), dbSettingsObj.getDBSID());
							   display.asyncExec(new Runnable() {
								   public void run() {
									   // If user logged in successfully
									   if (DBInstance!=null) {
										   statusLabel.setText("Logged in to DB");
										   DBflag=true;
										   shell.close();
										}
									   // Wrong login information or any other error
									   else {
										   statusLabel.setText("Error, please try again or check the log");
										   loginButton.setEnabled(true);
									   }
								   	}
							   });
						   }
					});
				   } catch (InterruptedException e1) {
					   if (logReady)
		 				{
							myLogger.log(2,"an error occured, please check the logs for more details");
							myLogger.log(2, e1.getMessage());
							
		 				}
				   }
			   }
		   });
	    shell.pack();
		SWTUtil.openShell(shell);
		
	}
   
   
	/**
	 * Upon opening the program, login page generated by this function will be presented to the user
	 */
   public static void showLoginShell() {

	   final Shell shell = SWTwin.getShell();
	   final Display display = shell.getDisplay();
 
	   shell.setText("Log In");
	   shell.setLayout(new GridLayout(2, false)); // 2 columns, same width

	   final GridData welcomeDoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
	   welcomeDoubleSpan.horizontalSpan = 2;

	   Font welcomeFont = new Font(display, "Arial",10,SWT.BOLD); 
	   
	   Label welcomeTitle = new Label(shell, SWT.RIGHT);
	   welcomeTitle.setText("Welcome to Songs I Like");
	   welcomeTitle.setLayoutData(welcomeDoubleSpan);
	   welcomeTitle.setFont(welcomeFont);
	   
	   
	   // Username
	   new Label(shell, SWT.RIGHT).setText("Username:");
	   final Text userText = new Text(shell, SWT.BORDER);
		
	   // Password
	   new Label(shell, SWT.RIGHT).setText("Password:");
	   final Text passwordText = new Text(shell, SWT.BORDER | SWT.PASSWORD);
		
	   // Login Button
	   final Button loginButton = new Button(shell, SWT.PUSH | SWT.FLAT);
	   loginButton.setText("Log In");
	   final GridData loginButtondoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
	   loginButtondoubleSpan.horizontalSpan = 2;
	   loginButton.setLayoutData(loginButtondoubleSpan);
	   
	   // Status Label (information about the status)
	   final Label statusLabel = new Label(shell, SWT.CENTER);
	   final GridData statusLabeldoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
	   statusLabeldoubleSpan.horizontalSpan = 2;
	   statusLabel.setLayoutData(statusLabeldoubleSpan);
	   
	   // Login button Listener
	   loginButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   final String userAsync=userText.getText();
			   final String passwordAsyn= passwordText.getText();
			   // Disable button to prevent multiple clicks during validation
			   loginButton.setEnabled(false);
			   try {
				pool.execute(new Runnable(){
					   public void run() {
						   DBInstance.ValidateUser(userAsync, passwordAsyn, currentUser);
						   display.asyncExec(new Runnable() {
							   public void run() {
								   // If user logged in successfully
								   if (currentUser.isLoggedin()) {
									   statusLabel.setText("Logged In");
									   shell.close();
								   }
								   // Wrong login information or any other error
								   else {
									   statusLabel.setText("Error, please try again");
									   loginButton.setEnabled(true);
								   }
							   	}
						   });
					   }
				});
			   } catch (InterruptedException e1) {
				   if (logReady)
	 				{
						myLogger.log(2,"an error occured, please check the logs for more details");
						myLogger.log(2, e1.getMessage());
						
	 				}
			   }
		   }
	   });
	   
	   // Create new user button
	   final Button newUserButton = new Button(shell, SWT.PUSH | SWT.FLAT);
	   newUserButton.setText("Create a new user");
	   final GridData newUserButtondoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
	   newUserButtondoubleSpan.horizontalSpan = 2;
	   newUserButton.setLayoutData(newUserButtondoubleSpan);
	   
	   // If new user button clicked, generate a sign up page
	   newUserButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   // Remove create new user button
			   newUserButton.dispose();
			   final Label signupLabel = new Label(shell, SWT.CENTER);
			   signupLabel.setText("Create a new user");
			   final GridData signupLabeldoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
			   signupLabeldoubleSpan.horizontalSpan = 2;
			   signupLabel.setLayoutData(signupLabeldoubleSpan);
			   
			   // Username
			   new Label(shell, SWT.RIGHT).setText("Select username:");
			   final Text newUserText = new Text(shell, SWT.BORDER);
				
			   // Password
			   new Label(shell, SWT.RIGHT).setText("Select password:");
			   final Text newPasswordText = new Text(shell, SWT.BORDER | SWT.PASSWORD);
			   
			   // Genres List
			   new Label(shell, SWT.RIGHT).setText("Favorite Genre");		   
			   final Combo genreDropDown = new Combo(shell, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY); 
				   
				// Age
				new Label(shell, SWT.RIGHT).setText("Your Age");		   
				final Combo ageDropDown = new Combo(shell, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
				for (int i=0;i<=120;i++) {
					ageDropDown.add(Integer.toString(i));
				}
				   
			   // Sex
			   new Label(shell, SWT.RIGHT).setText("Your Sex");		   
			   final Combo sexDropDown = new Combo(shell, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
			   sexDropDown.add("Male");
			   sexDropDown.add("Female");

			   // Continent
			   new Label(shell, SWT.RIGHT).setText("Select your continent");		   
			   final Combo continentDropDown = new Combo(shell, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
				   
			   // Sign up button
			   final Button signupButton = new Button(shell, SWT.PUSH | SWT.FLAT);
			   signupButton.setText("Sign Up");
			   signupLabel.setText("Create a new user");
			   final GridData signupButtondoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
			   signupButtondoubleSpan.horizontalSpan = 2;
			   signupButton.setLayoutData(signupButtondoubleSpan);
			   // We will disable this sign up button until user has filled in all required fields
			   signupButton.setEnabled(false);
			   shell.pack();
			   
			   // Fill in genres combo list with info from the DB
			   try {
					pool.execute(new Runnable(){
						   public void run(){
							   genres=DBInstance.getDBGenres();
							   display.asyncExec(new Runnable() {
								   public void run() {
									   if (genres!=null) 
										   for (Object genre: genres.keySet()) {
											   genreDropDown.add((String) genre);
										   }
									   // If failed, disable signup button and print error msg
									   else {
										   signupButton.setVisible(false);
										   statusLabel.setText("Error, please try again");
									   }
								   	}
							   });
						   }
					});
				} catch (InterruptedException e1) {
					myLogger.log(2, e1.getMessage());
				}

				// Fill in continents combo list with info from the DB				
				try {
					pool.execute(new Runnable(){
						public void run(){
							continents=DBInstance.getDBContinents();
							display.asyncExec(new Runnable() {
								public void run() {
									if (continents!=null)
										for (Object continent: continents.keySet()) {
											continentDropDown.add((String) continent);
										}
									   // If failed, disable signup button and print error msg
									else {
										   signupButton.setVisible(false);
										   statusLabel.setText("Error, please try again");
									}
								}
							});
						}
					});
				} catch (InterruptedException e1) {
					if (logReady)
					{
						myLogger.log(2,"an error has occured, please check the logs for mr details");
						myLogger.log(2, e1.getMessage());
					}
				}

				/* Begin combo lists listeners: 
				 * Every time a user fills one of the required fields, we
				 * increase a counter. Once the counter equals to the number of all the required fields 
				 * (numOfElements) we enable the sign up button using conuntElements() function */
				
				genreDropDown.addSelectionListener(new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						conuntElements(signupButton);
					}
				});
				continentDropDown.addSelectionListener(new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						conuntElements(signupButton);
					}
				});
				sexDropDown.addSelectionListener(new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						conuntElements(signupButton);
					}
				});
				ageDropDown.addSelectionListener(new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						conuntElements(signupButton);
					}
				});
				/* End combo lists listener */
				
				// If user clicked the sign up button, insert his data to the DB
				signupButton.addSelectionListener(new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						try {
							// Retrieve all filled data
						   final String newUserAsync=newUserText.getText();
						   final String newPasswordAsync=newPasswordText.getText();
						   final String newUserContinentName=continentDropDown.getText();
						   final String newUserGenreName=genreDropDown.getText();
						   final String newUserAge=ageDropDown.getText();
						   final int newUserSex;
						   if (sexDropDown.getText().equals("Male")) newUserSex=1;
						   else newUserSex=2;
						   
						   pool.execute(new Runnable(){
							   	public void run(){
							   		final int resMsg;							
							   		resMsg = DBInstance.SignupUser(newUserAsync,newPasswordAsync,continents.get(newUserContinentName),genres.get(newUserGenreName),Integer.parseInt(newUserAge), newUserSex, currentUser);
								    display.asyncExec(new Runnable() {
									   public void run() {
										   // Successfully signed up user
										   if (resMsg==1) {
											   statusLabel.setText("Login Successful");
											   shell.dispose();
										   }
										   // Error while signing up
										   else if (resMsg==0) statusLabel.setText("BAD username/password");
										   else if (resMsg==-1) statusLabel.setText("Username already exists");
										   else if (resMsg==-2) {
											   if (logReady) {
									  				myLogger.log(2,"can not connect to DB. please check the log for more details");
									  				statusLabel.setText("Cannot connect to DB");
									  			}
										   }
									   }
								   });
							   }
						   });
						} catch (InterruptedException e1) {
							if (logReady){
								myLogger.log(2, "unknown exception");
								myLogger.log(2, e1.getMessage());
							}
						}
					}
				});
		   }
	   });
	   
	   
	   shell.pack();
	   SWTUtil.openShell(shell);
   }
   
   /**
    * Main program window, contains all tabs
    */
   public static void showMainShell() {
	   final Shell shell = SWTwin.getShell();
	   final Display display = shell.getDisplay();
	   final TabFolder tabFolder = new TabFolder (shell, SWT.NONE);
	   
	   // Adding 6 tabs: "Search for Songs", "Recommend by user profile", "Recommend by user liked songs", "Insert a new CD", "Upload a File" and "Logout"
	   TabItem SearchItem = new TabItem (tabFolder, SWT.NULL);
	   TabItem RecommendItem = new TabItem (tabFolder, SWT.NULL);
	   TabItem CFItem = new TabItem (tabFolder, SWT.NULL);
	   TabItem manualInsertItem = new TabItem(tabFolder,SWT.NULL);
	   TabItem UploadItem = new TabItem (tabFolder, SWT.NULL);
	   TabItem LogoutItem = new TabItem (tabFolder, SWT.NULL);
	   
	   shell.setText("Songs I Like");
	   
	   /*
	    * Begin "Search for Songs" tab
	    */
	   
	   final Composite compositeSearch = new Composite(tabFolder, SWT.NONE);
	   compositeSearch.setLayout(new GridLayout(3, true)); // 3 columns, same width
	   
	   // Begin design of search form
	   new Label(compositeSearch, SWT.RIGHT).setText("Search by artist");
	   new Label(compositeSearch, SWT.RIGHT).setText("Search by CD");
	   new Label(compositeSearch, SWT.RIGHT).setText("Search by song");
	   
	   
	   final Text artistName = new Text(compositeSearch, SWT.BORDER);
	   final Text CDName = new Text(compositeSearch, SWT.BORDER);
	   final Text songName = new Text(compositeSearch, SWT.BORDER);

	   final Button artistCheck = new Button(compositeSearch, SWT.CHECK);
	   artistCheck.setText("excact phrase");
	   final Button CDCheck = new Button(compositeSearch, SWT.CHECK);
	   CDCheck.setText("excact phrase");
	   final Button songCheck = new Button(compositeSearch, SWT.CHECK);
	   songCheck.setText("excact phrase");
	   
	   final GridData spaceLabel1triplespan = new GridData(GridData.FILL_HORIZONTAL);
	   spaceLabel1triplespan.horizontalSpan = 3; // span 3 columns
	   
	   // Space label
	   final Label spaceLabel1 = new Label(compositeSearch, SWT.LEFT);
	   spaceLabel1.setLayoutData(spaceLabel1triplespan);
	   
	   new Label(compositeSearch, SWT.RIGHT).setText("Search by Genre");

	   new Label(compositeSearch, SWT.RIGHT).setText("Search by Decade");
	   new Label(compositeSearch, SWT.RIGHT);
	   
	   // Genres combo list
	   final Combo searchGenreDropDown = new Combo(compositeSearch, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
	   // Fill in continents combo list with info from the DB
	   try {
			pool.execute(new Runnable(){
				   public void run(){
					   genres=DBInstance.getDBGenres();
					   display.asyncExec(new Runnable() {
						   public void run() {
							   searchGenreDropDown.add("All");
							   for (Object genre: genres.keySet()) {
								   searchGenreDropDown.add((String) genre);
							   }
							   searchGenreDropDown.select(0);
						   	}
					   });
				   }
			});
		   } catch (InterruptedException e1) {
			if (logReady){
				myLogger.log(2, "unknown exception");
				myLogger.log(2, e1.getMessage());
			}
		}
	   // Decade combo list
	   final Combo searchDecadeDropDown = new Combo(compositeSearch, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
	   searchDecadeDropDown.add("All");
	   for (int i=1;i<=9;i++) {
		   searchDecadeDropDown.add(Integer.toString(i*10)+ "'s");
	   }
	   searchDecadeDropDown.add("2000+");
	   searchDecadeDropDown.select(0);
	   
	   // Search button
	   final Button searchButton = new Button(compositeSearch, SWT.PUSH | SWT.FLAT);
	   searchButton.setText("Search Now!");
	  
	   // Space label
	   final Label spaceLabel2 = new Label(compositeSearch, SWT.LEFT);
	   final GridData spaceLabel2triplespan = new GridData(GridData.FILL_HORIZONTAL);
	   spaceLabel2triplespan.horizontalSpan = 3; // span 3 columns
	   spaceLabel2.setLayoutData(spaceLabel2triplespan);
	   
	   // Result text
	   final Label resultText = new Label(compositeSearch, SWT.CENTER);
	   final GridData resultTexttriplespan = new GridData(GridData.FILL_HORIZONTAL);
	   resultTexttriplespan.horizontalSpan = 3; // span 3 columns
	   resultText.setLayoutData(resultTexttriplespan);
	   Font font = new Font(display, "Arial",10,SWT.BOLD); 
	   resultText.setFont(font);
	   resultText.pack();
	   
	   // Back button
	   final Button backButton = new Button(compositeSearch, SWT.PUSH | SWT.FLAT);
	   backButton.setText("<< Back");
	   backButton.pack();
	   backButton.setVisible(false);
	   
	   // Next button
	   final Button nextButton = new Button(compositeSearch, SWT.PUSH | SWT.FLAT);
	   nextButton.setText("Next >>");
	   nextButton.pack();
	   nextButton.setVisible(false);
	   
	   // Edit button
	   final Button editButton = new Button(compositeSearch, SWT.PUSH | SWT.FLAT);
	   editButton.setText("Edit Song");
	   editButton.pack();
	   editButton.setVisible(false);
	   editButton.setEnabled(false);
	   
	   // Error msg to display (when likes returns error, etc)
	   final Label errorMsg=new Label(compositeSearch, SWT.CENTER);
	   final GridData errorMsgtriplespan = new GridData(GridData.FILL_HORIZONTAL);
	   errorMsgtriplespan.horizontalSpan = 3; // span 3 columns
	   errorMsg.setLayoutData(errorMsgtriplespan);
	   
	   // Search results table
	   final Table resTable = new Table (compositeSearch, SWT.CHECK | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
	   resTable.setLinesVisible (true);
	   resTable.setHeaderVisible (true);
	   resTable.setVisible(false);
	   final GridData resTabletriplespan = new GridData(GridData.FILL_HORIZONTAL);
	   resTabletriplespan.horizontalSpan = 3; // span 3 columns
	   resTable.setLayoutData(resTabletriplespan);
	   
	   // Titles of results table
	   final String[] titles = {"Like", "Song Name", "Artist", "CD Name" , "Genre", "Year"};
	   
	   /* 
	    * Begin enabling sorting by columns 
	   */
	   
	   TableColumn column0 = new TableColumn (resTable, SWT.NONE);
	   column0.setText ("Like");
	   column0.addListener(SWT.Selection, new Listener() {
		      public void handleEvent(Event e) {
		    	  sortColumn(0, resTable);
		      }
	   });
	   
	   TableColumn column1 = new TableColumn (resTable, SWT.NONE);
	   column1.setText ("Song Name");
	   column1.addListener(SWT.Selection, new Listener() {
		      public void handleEvent(Event e) {
		    	  sortColumn(1, resTable);
		      }
		    });
	   
	   TableColumn column2 = new TableColumn (resTable, SWT.NONE);
	   column2.setText ("Artist");
	   column2.addListener(SWT.Selection, new Listener() {
		      public void handleEvent(Event e) {
		    	  sortColumn(2, resTable);
		      }
		    });
	   
	   TableColumn column3 = new TableColumn (resTable, SWT.NONE);
	   column3.setText ("CD Name");
	   column3.addListener(SWT.Selection, new Listener() {
		      public void handleEvent(Event e) {
		    	  sortColumn(3, resTable);
		      }
		    });
	   
	   TableColumn column4 = new TableColumn (resTable, SWT.NONE);
	   column4.setText ("Genre");
	   column4.addListener(SWT.Selection, new Listener() {
		      public void handleEvent(Event e) {
		    	  sortColumn(4, resTable);
		      }
		    });
	   
	   TableColumn column5 = new TableColumn (resTable, SWT.NONE);
	   column5.setText ("Year");
	   column5.addListener(SWT.Selection, new Listener() {
		      public void handleEvent(Event e) {
		    	  sortColumn(5, resTable);
		      }
		    });
	   /* 
	    * End enabling sorting by columns
	   */
	   
	   // If search button was click, initiate the search
	   searchButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try {
				   // Retrieve search arguments 
				   searchArtistCheck=artistCheck.getSelection();
				   searchCDCheck=CDCheck.getSelection();
				   searchSongCheck=songCheck.getSelection();
				   searchArtistName=artistName.getText();
				   searchCDName=CDName.getText();
				   searchsongName=songName.getText();
				   resultOffset=0;
			    
				   // Get the selected ID form genres (0 is returned if selected all)
				   if (searchGenreDropDown.getSelectionIndex()==0) {
					   searchGenreId=0;
					   searchChosenGenre="All";
				   }
				   else {
					   searchGenreId=genres.get(searchGenreDropDown.getText());
					   searchChosenGenre=searchGenreDropDown.getText();
				   }
			    
				   // Get the selected decade
				   if (searchDecadeDropDown.getSelectionIndex()==0) {
					   searchDecade=0;
					   searchChosenDecade="All";
				   }
				   else {
					   searchDecade=searchDecadeDropDown.getSelectionIndex()*10;
					   searchChosenDecade=searchDecadeDropDown.getText();
				   }
				   // Get search results from DB
				   pool.execute(new Runnable(){
					   public void run(){
						   resultsQuery=DBInstance.SelectSongs(searchArtistName, searchCDName, searchsongName,searchArtistCheck,searchCDCheck,searchSongCheck, searchGenreId, searchDecade);
						   display.asyncExec(new Runnable() {
							   public void run() {
								   errorMsg.setText("");
								   // If returned results for search, set functionality of search page
								   if (resultsQuery!=null){
									   backButton.setVisible(true);
									   nextButton.setVisible(true);
									   editButton.setVisible(true);
									   editButton.setEnabled(false);
									   setButtonsVisibility(backButton, nextButton, 1);
									   updateResTable(resTable, resultText, titles, 1);
									   clearSelected();
									   if (resultsQuery.size()==0)
										   errorMsg.setText("No Results");
								   }
								   else {
									   errorMsg.setText("DB Error, check log");
								   }
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });
	   
	   /* 
	    * Begin handling of "back", "next" and "edit" buttons on the search page.
	    * These buttons are enabled/visible only after a user committed a search.
	    */
	   backButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
				try {
					pool.execute(new Runnable(){
						   public void run(){			   
							   resultOffset--;
							   display.asyncExec(new Runnable() {
								   public void run() {
									   setButtonsVisibility(backButton, nextButton, 1);
									   updateResTable(resTable, resultText, titles, 1);
								   }
							   });
						   }
					});
					shell.pack();
				} catch (InterruptedException e1) {
					myLogger.log(2, "an error has occured");
					myLogger.log(2, e1.getMessage());
				}
		   }
	   });
	   
	   nextButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try {
				   pool.execute(new Runnable(){
					   public void run(){   
						   resultOffset++;
						   display.asyncExec(new Runnable() {
							   public void run() {
								   setButtonsVisibility(backButton, nextButton, 1);
								   updateResTable(resTable, resultText, titles, 1);
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });
	   
	   editButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   updateEntryInDB(rowNumSelected);	   
		   }
	   });
	   /*
	    * End handling of "back", "next" and "edit" buttons
	    */
	   
	   
	   // Listener for the search results table - used for checking the "Like" column and choosing a song to edit
	   resTable.addListener(SWT.Selection, new Listener() {
		   public void handleEvent(Event e) {

			   final TableItem eRow = (TableItem)e.item;
			   final boolean eRowCheck=eRow.getChecked();
			   final int eRowNum=Integer.parseInt(eRow.getText());
			   rowNumSelected=eRowNum;
        	  
			   // Add/Remove song from LIKES
			   if (e.detail == SWT.CHECK) {
				   try {
					   pool.execute(new Runnable(){
						   public void run(){
							   final int success;
							   Song currSong=resultsQuery.get(eRowNum);
							   if (eRowCheck)
								   success=DBInstance.InsertLike(new SongUID(currSong.getID(),currSong.getCid()), currentUser);
							   else
								   success=DBInstance.RemoveLike(new SongUID(currSong.getID(),currSong.getCid()), currentUser);
							   display.asyncExec(new Runnable() {
								   public void run() {
									   if (success!=1) {
										   errorMsg.setText("Error updating LIKE table");
									   }
								   }
							   });
						   }
					   });
				   } catch (InterruptedException e1) {
					   if (logReady){
						   myLogger.log(2, "unknown exception");
						   myLogger.log(2, e1.getMessage());
					   }
				   }
			   }
			   
	          // Edit Song
	          else
	          {
	        	  songNameSelected=eRow.getText(1);
	        	  artistNameSelected=eRow.getText(2);
	        	  cdNameSelected=eRow.getText(3);
	        	  genreNameSelected=eRow.getText(4);
	        	  yearSelected=eRow.getText(5);
	        	  editButton.setEnabled(true);
	          }
		   }
	   });

	   SearchItem.setText ("Search for Songs");
	   SearchItem.setControl(compositeSearch);
	   
	   /*
	    * End "Search for Songs" tab
	    */

	   /*
	    * Begin "Recommend by user profile" tab
	    */
	   
	   final Composite compositeRecoomend = new Composite(tabFolder, SWT.NONE);
	   compositeRecoomend.setLayout(new GridLayout(2, true)); // 2 columns, same width
	   
	   // Age Weight
	   new Label(compositeRecoomend, SWT.RIGHT).setText("Age:");		   
	   final Combo ageWeight = new Combo(compositeRecoomend, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
	   ageWeight.add("Not Important");
	   ageWeight.add("1");
	   ageWeight.add("2");
	   ageWeight.add("3");
	   ageWeight.add("4");
	   ageWeight.add("5");
	   ageWeight.select(5);
	   
	   // Sex Weight
	   new Label(compositeRecoomend, SWT.RIGHT).setText("Sex:");		   
	   final Combo sexWeight = new Combo(compositeRecoomend, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
	   sexWeight.add("Not Important");
	   sexWeight.add("1");
	   sexWeight.add("2");
	   sexWeight.add("3");
	   sexWeight.add("4");
	   sexWeight.add("5");
	   sexWeight.select(5);
	   
	   // Genre Weight
	   new Label(compositeRecoomend, SWT.RIGHT).setText("Genre:");		   
	   final Combo genreWeight = new Combo(compositeRecoomend, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
	   genreWeight.add("Not Important");
	   genreWeight.add("1");
	   genreWeight.add("2");
	   genreWeight.add("3");
	   genreWeight.add("4");
	   genreWeight.add("5");
	   genreWeight.select(5);
	   
	   // Continent Weight
	   new Label(compositeRecoomend, SWT.RIGHT).setText("Contitent:");		   
	   final Combo continentWeight = new Combo(compositeRecoomend, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
	   continentWeight.add("Not Important");
	   continentWeight.add("1");
	   continentWeight.add("2");
	   continentWeight.add("3");
	   continentWeight.add("4");
	   continentWeight.add("5");
	   continentWeight.select(5);
	   
	   // Find Button
	   final Button findButton = new Button(compositeRecoomend, SWT.PUSH | SWT.FLAT);
	   findButton.setText("Find Now!");
	   findButton.pack();
	   
	   // Create empty column
	   new Label(compositeRecoomend, SWT.RIGHT);	
	   
	   // Back Button
	   final Button backButtonRecom = new Button(compositeRecoomend, SWT.PUSH | SWT.FLAT);
	   backButtonRecom.setText("<< Back");
	   backButtonRecom.pack();
	   backButtonRecom.setVisible(false);
	   
	   // Next Button
	   final Button nextButtonRecom = new Button(compositeRecoomend, SWT.PUSH | SWT.FLAT);
	   nextButtonRecom.setText("Next >>");
	   nextButtonRecom.pack();
	   nextButtonRecom.setVisible(false);
	   
	   // Error msg to display (when likes returns error, etc)
	   final Label errorMsgRecom=new Label(compositeRecoomend, SWT.CENTER);
	   final GridData errorMsgRecomspan = new GridData(GridData.FILL_HORIZONTAL);
	   errorMsgRecomspan.horizontalSpan = 3; // span 3 columns
	   errorMsgRecom.setLayoutData(errorMsgRecomspan);
	   
	   // Recommendations results table
	   final Table resTableRecom = new Table (compositeRecoomend, SWT.CHECK | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
	   resTableRecom.setLinesVisible (true);
	   resTableRecom.setHeaderVisible (true);
	   resTableRecom.setVisible(false);
	   final GridData resTableRecomspan = new GridData(GridData.FILL_HORIZONTAL);
	   resTableRecomspan.horizontalSpan = 3; // span 3 columns
	   resTableRecom.setLayoutData(resTableRecomspan);
	  
	   // insert results table titles
	   for (int i=0; i<titles.length; i++) {
		   TableColumn column = new TableColumn (resTableRecom, SWT.NONE);
		   column.setText (titles [i]);
	   }
	   
	   /*
	    * Begin handling of "back" and "next" buttons
	    */
	   
	   backButtonRecom.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try { 
				   pool.execute(new Runnable(){
					   public void run(){
						   resultOffsetRecom--;
						   display.asyncExec(new Runnable() {
							   public void run() {
								   setButtonsVisibility(backButtonRecom, nextButtonRecom, 2);
								   updateResTable(resTableRecom, null, titles, 2);
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });
	   
	   nextButtonRecom.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try {
				   pool.execute(new Runnable(){
					   public void run(){
						   resultOffsetRecom++;
						   display.asyncExec(new Runnable() {
							   public void run() {
								   setButtonsVisibility(backButtonRecom, nextButtonRecom, 2);
								   updateResTable(resTableRecom, null, titles, 2);
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });
	   
	   /*
	    * End handling of "back" and "next" buttons
	    */
	   
	   // If find button was click, initiate the find recommendation search
	   findButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   // Retrieve search arguments
			   final String ageWeightText = ageWeight.getText();
			   final String sexWeightText = sexWeight.getText();
			   final String genreWeightText = genreWeight.getText();
			   final String continentWeightText = continentWeight.getText();
			   try {
				   resultOffsetRecom=0;
				   pool.execute(new Runnable(){
					   public void run(){
						   // Build weight array
						   int[] WeightNum = new int[4];
						   String currentProperty="";
						   for (int i=0;i<4;i++) {
							   if (i==0) currentProperty=ageWeightText;
							   else if (i==1) currentProperty=sexWeightText;
							   else if (i==2) currentProperty=genreWeightText;
							   else if (i==3) currentProperty=continentWeightText;
							   if (currentProperty.equals("Not Important"))
								   WeightNum[i]=0;
							   else 
								   WeightNum[i]=Integer.parseInt(currentProperty);
						   }
						   // Get recommendations from DB
						   try {
							   resultsQueryRecom=DBInstance.SelectRecom(currentUser,WeightNum);
						   } catch (SQLException e) {
							   if (logReady)
							   {
								   myLogger.log(2,"an error occured while accessing the DB. please check the log for more details");
								   myLogger.log(2, e.getMessage());
							   }
						   }
						   display.asyncExec(new Runnable() {
							   public void run() {
								   errorMsgRecom.setText("");
								   if (resultsQueryRecom!=null){
									   backButtonRecom.setVisible(true);
									   nextButtonRecom.setVisible(true);
									   setButtonsVisibility(backButtonRecom, nextButtonRecom, 2);
									   updateResTable(resTableRecom, null, titles, 2);
									   if (resultsQueryRecom.size() == 0)
										   errorMsgRecom.setText("No matches were found!");
								   }
								   else {
									   errorMsgRecom.setText("DB Error, check log");
								   }
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });	   
	   
	   resTableRecom.addListener(SWT.Selection, new Listener() {
		   public void handleEvent(Event e) {

        	  final TableItem eRow = (TableItem)e.item;
        	  final boolean eRowCheck=eRow.getChecked();
        	  final int eRowNum=Integer.parseInt(eRow.getText());
	          if (e.detail == SWT.CHECK) {
					try {
						pool.execute(new Runnable(){
							   public void run(){
								   final int success;
								   Song currSong=resultsQueryRecom.get(eRowNum);

								   if (eRowCheck) {
									   success=DBInstance.InsertLike(new SongUID(currSong.getID(),currSong.getCid()), currentUser);
								   }
								   else {
									   success=DBInstance.RemoveLike(new SongUID(currSong.getID(),currSong.getCid()), currentUser);
								   }
								   display.asyncExec(new Runnable() {
									   public void run() {
										   if (success!=1) {
											   errorMsgRecom.setText("Error updating LIKE table");
										   }
									   }
								   });
							   }
						});
					} catch (InterruptedException e1) {
						if (logReady){
							myLogger.log(2, "an error has occured");
				  			myLogger.log(2, e1.getMessage());
						}
							
					}

	          }
		   }
	   });

	   RecommendItem.setText ("Recommend by user profile");
	   RecommendItem.setControl(compositeRecoomend);

	   /*
	    * End "Recommend by user profile" tab
	    */
	   
	   /*
	    * Begin "Recommend by user liked songs" (collaborative filtering) tab
	    */
	   
	   final Composite compositeCF = new Composite(tabFolder, SWT.NONE);
	   compositeCF.setLayout(new GridLayout(6, true)); // 6 columns, same width
	   CFItem.setText ("Recommend by user liked songs");
	   CFItem.setControl(compositeCF);

	   final Button CFbutton = new Button(compositeCF, SWT.PUSH | SWT.FLAT);
	   CFbutton.setText("Lets try to find you a match by personal taste");
	   final GridData CFbuttonGrid = new GridData(GridData.FILL_HORIZONTAL);
	   CFbuttonGrid.horizontalSpan = 3;
	   CFbutton.setLayoutData(CFbuttonGrid);
	   CFbutton.pack();
	   
	   // Error msg to display (when likes returns error, etc)
	   final Label errorMsgCF=new Label(compositeCF, SWT.CENTER);
	   final GridData resultTextCFspan = new GridData(GridData.FILL_HORIZONTAL);
	   resultTextCFspan.horizontalSpan = 3; // span 3 columns
	   errorMsgCF.setLayoutData(resultTextCFspan);
	   errorMsgCF.pack();
	   
	   // Back button
	   final Button backButtonCF = new Button(compositeCF, SWT.PUSH | SWT.FLAT);
	   backButtonCF.setText("<< Back");
	   backButtonCF.pack();
	   backButtonCF.setVisible(false);
	   
	   // Next button
	   final Button nextButtonCF = new Button(compositeCF, SWT.PUSH | SWT.FLAT);
	   nextButtonCF.setText("Next >>");
	   nextButtonCF.pack();
	   nextButtonCF.setVisible(false);
	   
	   final Table resTableCF = new Table (compositeCF, SWT.CHECK | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
	   resTableCF.setLinesVisible (true);
	   resTableCF.setHeaderVisible (true);
	   resTableCF.setVisible(false);
	   GridData CFtableGrid = new GridData(GridData.FILL_HORIZONTAL);
	   CFtableGrid.horizontalSpan = 6;
	   resTableCF.setLayoutData(CFtableGrid);   
	   
	   // insert results table titles
	   for (int i=0; i<titles.length; i++) {
		   TableColumn column = new TableColumn (resTableCF, SWT.NONE);
		   column.setText (titles [i]);
	   }
	   

	   /*
	    * Begin handling of "back" and "next" buttons
	    */
	   
	   backButtonCF.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try { 
				   pool.execute(new Runnable(){
					   public void run(){
						   resultOffsetCF--;
						   display.asyncExec(new Runnable() {
							   public void run() {
								   setButtonsVisibility(backButtonCF, nextButtonCF, 3);
								   updateResTable(resTableCF, null, titles, 3);
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });
	   
	   nextButtonCF.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try {
				   pool.execute(new Runnable(){
					   public void run(){
						   resultOffsetCF++;
						   display.asyncExec(new Runnable() {
							   public void run() {
								   setButtonsVisibility(backButtonCF, nextButtonCF, 3);
								   updateResTable(resTableCF, null, titles, 3);
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });
	   
	   /*
	    * End handling of "back" and "next" buttons
	    */
	   
	   // If CF button was click, search for recommendations according to the basic CF Alg'
	   
	    CFbutton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   try {
				   resultOffsetCF=0;
				   pool.execute(new Runnable(){
					   public void run(){
						   // Get recommendations from DB
						   try {
							   resultsQueryCF=DBInstance.SelectSongsByCF(currentUser);
						   } catch (SQLException e) {
							   if (logReady)
							   {
								   myLogger.log(2,"an error occurred while accessing the DB. please check the log for more details");
								   myLogger.log(2, e.getMessage());
							   }
						   }
						   display.asyncExec(new Runnable() {
							   public void run() {
								   errorMsgCF.setText("");
								   if (resultsQueryCF!=null){
									   backButtonCF.setVisible(true);
									   nextButtonCF.setVisible(true);
									   setButtonsVisibility(backButtonCF, nextButtonCF, 3);
									   updateResTable(resTableCF, null, titles, 3);
									   if (resultsQueryCF.size() == 0)
										   errorMsgCF.setText("No matches were found!");
								   }
								   else {
									   errorMsgCF.setText("DB Error, check log");
								   }
								   
							   }
						   });
					   }
				   });
				   shell.pack();
			   } catch (InterruptedException e1) {
				   if (logReady){
					   myLogger.log(2, "unknown exception");
					   myLogger.log(2, e1.getMessage());
				   }
			   }
		   }
	   });	
	     
	    
	   resTableCF.addListener(SWT.Selection, new Listener() {
		   public void handleEvent(Event e) {

        	  final TableItem eRow = (TableItem)e.item;
        	  final boolean eRowCheck=eRow.getChecked();
        	  final int eRowNum=Integer.parseInt(eRow.getText());
	          if (e.detail == SWT.CHECK) {
					try {
						pool.execute(new Runnable(){
							   public void run(){
							    	  final int success;
						    		  Song currSong=resultsQueryCF.get(eRowNum);
							    	  if (eRowCheck) {
							    		  success=DBInstance.InsertLike(new SongUID(currSong.getID(),currSong.getCid()), currentUser);
							    	  }
							    	  else {
							    		  success=DBInstance.RemoveLike(new SongUID(currSong.getID(),currSong.getCid()), currentUser);
							    	  }
							    	  display.asyncExec(new Runnable() {
										   public void run() {
											   if (success!=1) {
												   errorMsgCF.setText("Error updating LIKE table");
											   }
										   }
									   });
							    	  
							   }
						});
					} catch (InterruptedException e1) {
						if (logReady){
							   myLogger.log(2, "an error has occured");
							   myLogger.log(2, e1.getMessage());
						   }
					}

	          }
		   }
	   });


	   /*
	    * end "Recommend by user liked songs" (collaborative filtering) tab
	    */
	   
	   
	   /*
	    * Begin "Insert a new CD" tab
	    */
	   
	   // Design of tab 
	   final Composite compositeInsert= new Composite (tabFolder,SWT.NONE);
	   compositeInsert.setLayout(new GridLayout(2,false));
	   
	   new Label(compositeInsert, SWT.RIGHT).setText("Artist name");
	   final Text artistNameInsert = new Text(compositeInsert, SWT.BORDER);
	   
	   new Label(compositeInsert, SWT.RIGHT).setText("Disc name");
	   final Text discNameInsert = new Text(compositeInsert, SWT.BORDER);
	   
	   new Label(compositeInsert, SWT.RIGHT).setText("Genre name");
	   final Text genreNameInsert = new Text(compositeInsert, SWT.BORDER);
	   
	   new Label(compositeInsert, SWT.RIGHT).setText("Year");
	   final Text yearInsert = new Text(compositeInsert, SWT.BORDER);
	   
	   final Button addToDBButton = new Button(compositeInsert, SWT.PUSH | SWT.FLAT);
	   addToDBButton.setText("Add to DB");
	   addToDBButton.pack();
	   
	   // Table for inserting the disc's songs
	   final Table insertTable = new Table (compositeInsert, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
	   
	   // Label for printing fail/success msg after trying to add disc to DB
       final Label msgAddToDb = new Label(compositeInsert, SWT.CENTER);
       
	   final GridData msgAddToDbdoubleSpan = new GridData(GridData.FILL_HORIZONTAL);
	   msgAddToDbdoubleSpan.horizontalSpan = 2; // span 2 columns
	   
	   msgAddToDb.setLayoutData(msgAddToDbdoubleSpan);
	   
	   insertTable.setLinesVisible (true);
	   insertTable.setHeaderVisible (true);
	   
	   // Design "insert songs" table
	   GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
	   data.heightHint = 200;
	   insertTable.setLayoutData(data);
	   String[] titlesInsert = {"Track Number","Song Name"};
	   for (int i=0; i<titlesInsert.length; i++) {
			TableColumn column = new TableColumn (insertTable, SWT.NONE);
			column.setText (titlesInsert [i]);
		}
		
		final int count = 20;
		for (int i=1; i<=count; i++) {
			TableItem item = new TableItem (insertTable, SWT.NONE);
			item.setText (0, String.valueOf(i));
			item.setText (1, "");
		}
		// Set table size
		insertTable.setSize(550, 200);
		// Set width of "Track Number" column
		insertTable.getColumn(0).setWidth(100);
		// Set width of "Song Name" column
		insertTable.getColumn(1).setWidth(450);
		
		final TableEditor insertEditor = new TableEditor(insertTable);
		/* The editor must have the same size as the cell and must
		/ not be any smaller than 50 pixels.*/
		insertEditor.horizontalAlignment = SWT.LEFT;
		insertEditor.grabHorizontal = true;
		insertEditor.minimumWidth = 50;
		// Enabling edit of the second column
		final int EDITABLECOLUMN = 1;
		
		insertTable.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				// Clean up any previous editor control
				Control oldEditor = insertEditor.getEditor();
				if (oldEditor != null) oldEditor.dispose();
		
				// Identify the selected row
				TableItem item = (TableItem)e.item;
				if (item == null) return;
		
				// The control that will be the editor must be a child of the Table
				Text newEditor = new Text(insertTable, SWT.NONE);
				newEditor.setText(item.getText(EDITABLECOLUMN));
				newEditor.addModifyListener(new ModifyListener() {
					public void modifyText(ModifyEvent me) {
						Text text = (Text)insertEditor.getEditor();
						insertEditor.getItem().setText(EDITABLECOLUMN, text.getText());
					}
				});
				newEditor.selectAll();
				newEditor.setFocus();
				insertEditor.setEditor(newEditor, item, EDITABLECOLUMN);
			}
		});
		
		// If add to DB button was clicked, initiate insert to DB
		addToDBButton.addSelectionListener(new SelectionAdapter() {
			   public void widgetSelected(final SelectionEvent e) {
				   // Retrieve insert to DB arguments
				   final Map<Integer,String> songs= new HashMap<Integer,String>();
				   final String addDiscName=discNameInsert.getText();
				   final String addArtistName=artistNameInsert.getText();
				   final String addGenreName=genreNameInsert.getText();
				   final String addYear=yearInsert.getText();
				   int counter=1;
				   for (int i=0;i<count;i++){
					   if(insertTable.getItem(i).getText(1)!="")
					   {
					   songs.put(counter++,insertTable.getItem(i).getText(1));
					   }
				   }
				   // Insert disc to DB
				   try {
					   addToDBButton.setEnabled(false);
					   pool.execute(new Runnable(){
						   public void run(){
							   final int success;
							   success=DBOperations.addManually(addDiscName.toLowerCase(), addArtistName.toLowerCase(), addGenreName.toLowerCase(), addYear, songs);
							   display.asyncExec(new Runnable() {
								   public void run() {
									   if (success==0) msgAddToDb.setText("ERROR adding CD, please check the entred parameters");
									   else if(success==-1) {
										   if (logReady) {
											   myLogger.log(2,"can not connect to DB. please check the log for more details");
										   }
										   msgAddToDb.setText("DB Error, check log");
									   }
									   else if (success==1) msgAddToDb.setText("CD added successfully");
									   addToDBButton.setEnabled(true);
								   }
							   });
						   }
					   });
				   }
				   catch (InterruptedException e1) {
					   if (logReady) {
						   myLogger.log(2,"an error has occured. please check the log for more details");
						   myLogger.log(2, e1.getMessage());
					   }
				   }
			   }
		});

		manualInsertItem.setText("Insert a new CD");
		manualInsertItem.setControl(compositeInsert);
		/*
		 * End "Insert a new CD" tab
		 */

		/*
		 * Begin "Upload a File" tab
		 */
		final Composite compositeUpload = new Composite(tabFolder, SWT.NONE);
		compositeUpload.setLayout(new GridLayout(1, true)); // 2 columns, same width
		
		// Browse text
		Label browseLabel = new Label(compositeUpload, SWT.BOLD);
		browseLabel.setText("Browse File");
		browseLabel.setFont(font);
	   
		// Title label
		new Label(compositeUpload, SWT.RIGHT).setText("Click below to browse a TAR file and upload to database");
	   
		// Browse Button
		final Button browseButton = new Button(compositeUpload, SWT.PUSH | SWT.FLAT);
		browseButton.setText("Browse...");
		browseButton.pack();
	   
		// Upload file name
		final Label uploadFileName = new Label(compositeUpload, SWT.LEFT);
		final GridData uploadFileNamespan = new GridData(GridData.FILL_HORIZONTAL);
		uploadFileNamespan.horizontalSpan = 3; // span 3 columns
		uploadFileName.setLayoutData(uploadFileNamespan);
		uploadFileName.pack();
		uploadFileName.setVisible(false);
	   
		// Upload Button
		final Button uploadButton = new Button(compositeUpload, SWT.PUSH | SWT.FLAT);
		uploadButton.setText("Upload File");
		uploadButton.pack();
		uploadButton.setVisible(false);
	   
		// If browse button was click, show "File Dialog"
		browseButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {   
				try {
					pool.execute(new Runnable(){
						   public void run(){
							   display.asyncExec(new Runnable() {
								   public void run() {
									   FileDialog dlg = new FileDialog(shell);
									   dlg.setText("Select File To Upload");
									   selectedFile = dlg.open();
									   if (selectedFile!=null) {
										   uploadFileName.setText("Selected File: " +selectedFile);
										   uploadFileName.setVisible(true);
										   uploadButton.setVisible(true);
									   }
									   else {
										   uploadFileName.setVisible(false);
										   uploadButton.setVisible(false);
									   }
								   }
							   });
						   }
					});
				}
				catch (InterruptedException e1) {
					if (logReady){
						myLogger.log(2, "an error has occured");
						myLogger.log(2, e1.getMessage());
					}
				}
			}
		});

		// If upload button was click, start uploading file to DB
		uploadButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
				try {
					browseButton.setEnabled(false);
					uploadButton.setEnabled(false);
					uploadFileName.setText("Now uploading...");
					// Start inserting to DB
					pool.execute(new Runnable(){
						public void run(){
							final int success=startUpload();
							display.asyncExec(new Runnable() {
								public void run() {
									if (success==0) uploadFileName.setText("Failed to upload file");
									else uploadFileName.setText("Uploaded file successfully");
									browseButton.setEnabled(true);
									uploadButton.setEnabled(true);
								}
							});
						}
					});
				}
				catch (InterruptedException e1) {
					myLogger.log(2, "an error has occured");
					myLogger.log(2, e1.getMessage());
				}
		   }
		});
	   	   
		UploadItem.setText ("Upload a File");
		UploadItem.setControl(compositeUpload);
		/*
		 * End "Upload a File" tab
		 */
		
		/*
		 * Begin "Logout" tab
		 */
		   
		// Design of tab 
		final Composite compositeLogout= new Composite (tabFolder,SWT.NONE);
		compositeLogout.setLayout(new GridLayout(2,true));
		
		
		// Browse Button
		final Button LogoutButton = new Button(compositeLogout, SWT.PUSH | SWT.FLAT);
		LogoutButton.setText("Logout");
		LogoutButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		LogoutButton.pack();

		// Browse Button
		final Button QuitButton = new Button(compositeLogout, SWT.PUSH | SWT.FLAT);
		QuitButton.setText("Quit");
		QuitButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		QuitButton.pack();
		
		// If logout button was click
		LogoutButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
			   currentUser.setLoggedin(false);
			   logout=1;
			   shell.close();
		   }
		});
		
		// If quit button was click
		QuitButton.addSelectionListener(new SelectionAdapter() {
		   public void widgetSelected(SelectionEvent e) {
				shell.close();
		   }
		});
		
		LogoutItem.setText("Logout/Quit");
		LogoutItem.setControl(compositeLogout);
		/*
		 * End "Logout" tab
		 */
		
		// Set size of tab
		tabFolder.setSize(700, 500);
	  
		shell.pack();
		SWTUtil.openShell(shell);
   }
   
   /**
    * Function updates a result table with the results returned from the DB
    * @param resTable - the SWT Table object to be updated
    * @param resultText - A title for the search query (featuring the search arguments)
    * @param titles - the Table columns titles
    * @param type - type==1 : Search for Discs tab,  type==2 : Recommendations tab 
    */
   public static void updateResTable(Table resTable, Label resultText, String[] titles, int type) {
	   Map<Integer, Song> currentResultsQuery;
	   int cuurentResultOffset=0;
	   
	   if (type==1) {
		   resultText.setText("Showing results for Arist: " + (searchArtistName.equals("") ? "All" : searchArtistName) + " ; Disc Name: " + (searchCDName.equals("") ? "All" : searchCDName) + " ; Song Title: "  + (searchsongName.equals("") ? "All" : searchsongName) + " ; Genre: " + searchChosenGenre + "; Decade: " + searchChosenDecade);
		   resTable.setVisible(true);
		   currentResultsQuery=resultsQuery;
		   cuurentResultOffset=resultOffset;
	   }
	   else if(type==2){
		   currentResultsQuery=resultsQueryRecom;
		   cuurentResultOffset=resultOffsetRecom;
	   }
	   else if(type==3){
		   currentResultsQuery=resultsQueryCF;
		   cuurentResultOffset=resultOffsetCF;
	   }
	   else{
		   currentResultsQuery=null;
	   }
	   resTable.removeAll();

	   // Show results within the given search page offset
	   for (int i=cuurentResultOffset*RESULT_PER_PAGE+1;i<=(cuurentResultOffset+1)*RESULT_PER_PAGE;i++) {
			    Song songDetails=currentResultsQuery.get(i);
			    if (songDetails==null) continue;
				TableItem item = new TableItem (resTable, SWT.CHECK | SWT.NONE);
				// Check if the user liked this song, if so - mark it as liked
				if (currentUser.inList(new SongUID(songDetails.getID(), songDetails.getCid()))!=-1) item.setChecked(true);
				item.setText (0, Integer.toString(i));
				
				String songTitle=songDetails.getSongTitle();
				String songArtist=songDetails.getArtist();
				String fixedTitle=fixSong(songTitle,songArtist);
				String fixedArtist=fixArtist(songTitle,songArtist);
				
				// Fill table with song info
				if (fixedTitle!=null)
					item.setText (1, fixedTitle);
				if (fixedArtist!=null)
					item.setText (2, fixedArtist);
				if (songDetails.getCdTitle()!=null)
					item.setText (3, songDetails.getCdTitle());
				if (songDetails.getGenre()!=null)
					item.setText (4, songDetails.getGenre());
				item.setText (5, songDetails.getYear()==0 ? "No Data" : Integer.toString(songDetails.getYear()));
	   }
	   // Set table's columns width 
	   for (int i=0; i<titles.length; i++) {
		   resTable.getColumn(i).setWidth(resTable.getSize().x/titles.length);
		}
	   resTable.setVisible(true);
	   resTable.setSize(650, 200);
   	}
   
   /**
    * Function sets the visibility of the "back" and "next" buttons according to the offset
    * @param backButton
    * @param nextButton
    * @param type - type==1 : Search for Discs tab,  type==2 : Recommendations tab 
    */
   public static void setButtonsVisibility(Button backButton, Button nextButton, int type) {
	   int currentOffset=0;
	   Map<Integer,Song> currResultsQuery=null;
	   if (type==1) {
		   currentOffset=resultOffset;
		   currResultsQuery=resultsQuery;
	   }
	   else if (type==2){
		   currentOffset=resultOffsetRecom;
		   currResultsQuery=resultsQueryRecom;
	   }
	   else if (type==3){
		   currentOffset=resultOffsetCF;
		   currResultsQuery=resultsQueryCF;		   
	   }
	   if (currentOffset==0) backButton.setEnabled(false);
	   else backButton.setEnabled(true);
	   if (currResultsQuery.size()-((currentOffset+1)*RESULT_PER_PAGE)<=0) nextButton.setEnabled(false);
	   else nextButton.setEnabled(true);
   }
   
   /**
    * Function uploads a TAR file to the DB
    * @return 0 if upload fails, 1 on success
    */
   public static int startUpload() {
  		int success=0;
  		try {
  			// Creates an import instance

  			if (logReady) myLogger.log(1,"function add to DB triggered");
  			// Uploads the file to DB
  			success=DBInstance.runImport(selectedFile,logReady,myLogger);

  			if (logReady) myLogger.log(1,"finished adding to DB");
  			
  		} catch (InstantiationException e) {
  			if (logReady) 
  				{
	  				myLogger.log(2, "can not create DB connection");
	  				myLogger.log(2, e.getMessage());
  				}
  			return 0;
  		} catch (IllegalAccessException e) {
  			if (logReady) 
				{
					myLogger.log(2, "can not create DB connection");
					myLogger.log(2, e.getMessage());
				}	
  			return 0;
  		} catch (ClassNotFoundException e) {
  			if (logReady) 
			{
				myLogger.log(2, "can not create DB connection");
				myLogger.log(2, e.getMessage());
			}
  			return 0;
		}
  		finally
  		{
  			myLogger.closeFileHandler();
  		}
  		return success;
   }
   /**
    * Function takes care of case when we are handling a disc which
    * is a collection: gets the name of song instead of artist
    * Here we fix the song
    * @param songName
    * @param artist
    * @return
    */
	private static String fixSong(String songName, String artist){
		if ((artist.equalsIgnoreCase("various"))||(artist.equalsIgnoreCase("diverse"))
				||(artist.equalsIgnoreCase("various artists"))||(artist.equalsIgnoreCase("collcection"))||
				(artist.equalsIgnoreCase("va"))||(artist.equalsIgnoreCase("v.a."))){
			
			// If we got here, it means we are looking at a collection
			if (songName.contains(" / ")){
				return (parseSong(songName," / "));	
			}
			if (songName.contains(" - ")){
				return (parseSong(songName," - "));
			}
			if (songName.contains(" : ")){
				return (parseSong(songName, " : "));
			}
		}
		// If we didn't enter the if, it is not a collection- we return the song
		return songName;
	}
	/**
    * Function takes care of case when we are handling a disc which
    * is a collection: gets the name of song instead of artist
    * Here we fix the artist
	* @param songName
	* @param artist
	* @return
	*/
	private static String fixArtist(String songName, String artist){
		if ((artist.equalsIgnoreCase("various"))||(artist.equalsIgnoreCase("diverse"))
				||(artist.equalsIgnoreCase("various artists"))||(artist.equalsIgnoreCase("collcection"))||
				(artist.equalsIgnoreCase("va"))||(artist.equalsIgnoreCase("v.a."))){
			
			// If we got here, it means we are looking at a collection
			if (songName.contains(" / ")){
				return (parseArtist(songName," / "));	
			}
			if (songName.contains(" - ")){
				return (parseArtist(songName," - "));
			}
			if (songName.contains(" : ")){
				return (parseArtist(songName, " : "));
			}
		}
		// If we didn't enter the if, it is not a collection- we return the song
		return artist;
	}
	/**
	 * Help function for fixSong - handling the delimiters
	 * @param songName
	 * @param str
	 * @return string of songName
	 */
	//
	private static String parseSong(String songName, String str){
		int indexDelimiter=songName.indexOf(str);
		if (indexDelimiter!=-1) return songName.substring(indexDelimiter+3);
		else{
			System.out.println ("unknown delimiter: "+str);
			return songName;
		}
	}
	//help method for fixArtist
	private static String parseArtist(String songName, String str){
		int indexDelimiter=songName.indexOf(str);
		if (indexDelimiter!=-1) return songName.substring(0, indexDelimiter);
		else{
			System.out.println ("unknown delimiter: "+str);
			return songName;
		}
	}
	
	/**
	 * Function edits a song in the DB (using a new window)
	 * @param row - row of the song to be added
	 */
	private static void updateEntryInDB(final int row) {
		final Shell updateSong = SWTwin.getShell();
		final Display display=updateSong.getDisplay();
		
		// Design update page
		updateSong.setSize (500, 500);
	
		updateSong.setText("Update Song");
		updateSong.setLayout(new GridLayout(2, false)); // 2 columns, same width
	
		new Label(updateSong, SWT.RIGHT).setText("Song name");
		final Text songName = new Text(updateSong, SWT.BORDER);

		new Label(updateSong, SWT.RIGHT).setText("Artist name");
		final Text artistName = new Text(updateSong, SWT.BORDER);

		new Label(updateSong, SWT.RIGHT).setText("Disc name");
		final Text discName = new Text(updateSong, SWT.BORDER);
		   
		new Label(updateSong, SWT.RIGHT).setText("Genre name");
		final Text genreName = new Text(updateSong, SWT.BORDER);
		   
		new Label(updateSong, SWT.RIGHT).setText("Year");
		final Text year = new Text(updateSong, SWT.BORDER);
	
		songName.setText(songNameSelected);
		artistName.setText(artistNameSelected);
		discName.setText(cdNameSelected);
		genreName.setText(genreNameSelected);
		year.setText(yearSelected);
			
		final Button updateButton = new Button(updateSong, SWT.PUSH | SWT.FLAT);
		updateButton.setText("Update in DB");
			  	
		final GridData data = new GridData(GridData.FILL_HORIZONTAL);
		data.horizontalSpan = 2; // span 2 columns
		updateButton.setLayoutData(data);
			   
		final Label errorMsg=new Label(updateSong, SWT.CENTER);
		errorMsg.setLayoutData(data);
		
		// If update button was clicked, update song in DB
		updateButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				// Disable button when updating
				updateButton.setEnabled(false);
				// Retrieve edit arguments
				final String songText=songName.getText();
				final String artistText= artistName.getText();
				final String discText=discName.getText();
				final String genreText=genreName.getText();
				final String yearText=year.getText();
				final long cdID=resultsQuery.get(row).getCid();
				final int trackNum=resultsQuery.get(row).getID();
				try {
					pool.execute(new Runnable(){
						public void run() {
							final int succ;
							// Update the DB with the edited song							   								   
							succ=DBOperations.updateManually(songText,artistText,
									discText,cdID,yearText,genreText,trackNum);
																	   
							display.asyncExec(new Runnable() {
								public void run() {
									if (succ==0) {
										errorMsg.setText("Bad Input");
										updateButton.setEnabled(true);
									}
									else if(succ==-1){
										updateButton.setEnabled(true);
										if (logReady) {
											myLogger.log(2, "can not create DB connection");
										}
									}
									// Success updating DB
									else {
										updateSong.close();
									}
								}
							});
						}
					});
				} catch (InterruptedException e1) {
					if (logReady) {
						myLogger.log(2,"an error occured. please check the log for more details");
						myLogger.log(2, e1.getMessage());
					}
				}
			}
		});
			   
		final Button closeUpdateShell = new Button(updateSong, SWT.PUSH | SWT.FLAT);
		closeUpdateShell.setText("cancel");
		closeUpdateShell.setLayoutData(data);
		
		// If cancel update was clicked, close window
		closeUpdateShell.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				updateSong.close();									  
			}
		});	
		updateSong.pack();
		updateSong.open ();
	}
	
	/**
	 * If a new search was made, clear the selected song to edit
	 */
	private static void clearSelected(){
		songNameSelected="";
		artistNameSelected="";
		cdNameSelected="";
		genreNameSelected="";
		yearSelected="";
		rowNumSelected=-1;
	}
	
	/**
	 * Sort search table columns
	 * @param id - column ID to sort
	 * @param resTable - result table to sort 
	 */
	public static void sortColumn(int id, Table resTable) {
		TableItem[] items = resTable.getItems();
		Collator collator = Collator.getInstance(Locale.getDefault());
		for (int i = 1; i < items.length; i++) {
			String value1 = items[i].getText(id);
			for (int j = 0; j < i; j++) {
				String value2 = items[j].getText(id);
				if (collator.compare(value1, value2) < 0) {
					String[] values = { items[i].getText(0),items[i].getText(1),items[i].getText(2),items[i].getText(3),
							items[i].getText(4),items[i].getText(5) };
					items[i].dispose();
					TableItem item = new TableItem(resTable, SWT.NONE, j);
					item.setText(values);
					items = resTable.getItems();
					break;
				}
			}
		}
	}
	/**
	 * Function counts the number of required fields filled by user on the sign up page
	 * If all required fields were filled, sign up button is enabled
	 * @param signupButton
	 */
	public static void conuntElements(Button signupButton) {
		   countSelection++;
		   if (countSelection==numOfElements) signupButton.setEnabled(true);
	   }
	 
	/**
	 * 
	 * @return logger
	 */
	public static logger getLogger(){
		return myLogger;		   
	}
}